package handin05;

import java.util.*;

/**
 * MagicSquare contains a sequence of numbers ordered in a square.
 *  
 * @author Peter Tolstrup Aagesen, ptaa@itu.dk *
 */
public class MagicSquare 
{
	//Create instance variable
	private ArrayList<Integer> square;
	
	/**
	 * 
	 */
	public MagicSquare()
	{
		//Initiate square
		square = new ArrayList<Integer>();		
	}
	
	/**
	 * add adds an integer to the square
	 * @param i
	 */
	public void add(int i)
	{
		//Add i to square
		square.add(i);
	}
	
	/**
	 * clearSquare empties the square
	 */
	public void clearSquare()
	{
		//Clear square
		square.clear();
	}
	
	/**
	 * isSquare validates if there are the correct number of integers in the square
	 * @return boolean
	 */
	public boolean isSquare()
	{
		//Create return value
		boolean returnValue = false;
		
		//Check and return if the the square root of the size of the array is an integer (correct size) 
		if (Math.sqrt(square.size())%1 == 0)
		{
			//Set return value to true
			returnValue = true;
		}
		
		//Return value
		return returnValue;
	}
	
	/**
	 * inCorrectNumberSequence validates the integers in the square
	 * The integers must be from 1 to n, with only one of each.
	 * @return boolean
	 */
	public boolean isCorrectNumberSequence()
	{
		//Create return value
		boolean returnValue = true;
		
		//Create a copy of the square
		ArrayList<Integer> squareCopy = new ArrayList<Integer>();
		for(Integer i: square)
		{
			squareCopy.add(i);
		}
		//Sort the array 
		Collections.sort(squareCopy);
		
		//Create variables
		int currentInt;
		int previousInt = 0;
		for (int i = 0; i < squareCopy.size(); i ++)
		{
			//Get value from square
			currentInt = squareCopy.get(i);
			
			//If the current integer is not 1 higher than the previous integer set return value to false and return
			if (currentInt != previousInt + 1) {
				returnValue = false;
				break;
			}			
			
			//Set previousInt value for next loop
			previousInt = currentInt;
		}
		
		//Return value
		return returnValue;
	}
	
	/**
	 * isMagic validates if the square is magic
	 * @return boolean
	 */
	public boolean isMagic()
	{
		//create return value
		boolean returnValue;
		
		//Start by checking if the input is correct
		if(isSquare() && isCorrectNumberSequence()) {
			//Set the return value to true
			returnValue = true;	
			
			//Get the width and height of the square
			int n = (int) Math.ceil(Math.sqrt(square.size()));
			
			//Create value for check sum
			int magicConstant = (n*(n*n + 1))/2;
			
			//Create variables to calculate sums
			int rowSum;
			int columnSum;
			int diagonalSum1 = 0;
			int diagonalSum2 = 0;
			
			//loop rows
			for(int y = 0; y < n; y ++)
			{
				//Set row and column sum to 0 on each loop
				rowSum = 0;
				columnSum = 0;	
				
				//loop columns
				for(int x = 0; x < n; x ++)
				{
					//Calculate row and column sum
					rowSum += square.get(x + y * n);					
					columnSum += square.get(x * n + y);
					
					//Calculate diagonal sums once
					if (y == 0) {
						diagonalSum1 += square.get(x * n + x);
						diagonalSum2 += square.get(x * n + n - (x + 1));
						if (x == n-1) { //check sums on last x loop
							if (diagonalSum1 != magicConstant || diagonalSum2 != magicConstant) {
								return false;
							}
						} 
					}
				}	
				
				//If sums are different from magicConstant set return value to false and break loop
				if (rowSum != magicConstant || columnSum != magicConstant) {
					returnValue = false;
					break;
				} 
			}
		} else {
			//If the input isn't valid set return value to false
			returnValue = false;
		}	
		//Return value
		return returnValue;
	}
	
	/**
	 * toString returns a String containing the integers in the square
	 */
	public String toString()
	{
		//Create variable for return value
		String returnValue = "";
		
		//If the ArrayList is empty return "| |"
		if (square.isEmpty()) {
			returnValue = "| |";
			return returnValue;
		} 
		
		//Get n or if n is not an integer; next integer n
		int n = (int) Math.ceil(Math.sqrt(square.size()));
		
		//Get square size from n
		int nn = n * n;
		
		//Declare i outside of for loop if I need it to fill out empty spaces
		int i;		
		
		//Print the values in square
		for(i = 0; i < square.size(); i ++)
		{			
			if(i % n == 0) { //Left value 
				returnValue += "| ";
			} 
			
			returnValue += square.get(i);
			
			if(i % n == n - 1) { //Right values 
				//Last right value doesn't need a new line
				if (i == nn - 1) returnValue += " |";
				//
				else returnValue += " |\n";
			} else { //The "rest"
				returnValue += ", ";
			}
		}
		
		//If the square isn't actually square fill out the rest with empty spaces
		for(int j = i; j < nn; j ++)
		{
			if(j % n == 0) {
				returnValue += "|  , ";
			} else if (j % n == n - 1) {
				if (j == nn - 1) returnValue += "  |";
				else returnValue += "  |\n";
			} else {
				returnValue += " , ";
			}
		}
		
		//Return value
		return returnValue;
	}
}
